package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.config.WebSocketServer;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.AlertNotifyDto;
import com.zzyl.dto.AlertRuleDto;
import com.zzyl.entity.AlertData;
import com.zzyl.entity.AlertRule;
import com.zzyl.mapper.AlertDataMapper;
import com.zzyl.mapper.AlertRuleMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.mapper.UserRoleMapper;
import com.zzyl.service.AlertRuleSecvice;
import com.zzyl.vo.AlertRuleVo;
import com.zzyl.vo.DeviceDataVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.github.pagehelper.Page;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class AlertRuleSecviceImpl implements AlertRuleSecvice {
    private static final Logger log = LoggerFactory.getLogger(AlertRuleSecviceImpl.class);
    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private AlertDataMapper alertDataMapper;
    @Autowired
    private WebSocketServer webSocketServer;
    @Override
    public void create(AlertRuleDto alertRuleDto) {
        AlertRule alertRule = BeanUtil.copyProperties(alertRuleDto, AlertRule.class);
        alertRuleMapper.create(alertRule);
    }

    @Override
    public PageResponse<AlertRuleVo> getPage(Integer pageNum, Integer pageSize, String alertRuleName, String productKey, String functionName) {
        PageHelper.startPage(pageNum, pageSize);
        Page<AlertRuleVo> page = alertRuleMapper.getPage(alertRuleName, productKey, functionName);
        page.getResult().forEach(alertRuleVo -> {
            String rules = CharSequenceUtil.format("{}{}{},持续{}个周期就报警",
                    alertRuleVo.getFunctionName(),
                    alertRuleVo.getOperator(),
                    alertRuleVo.getValue(),
                    alertRuleVo.getDuration());
            alertRuleVo.setRules(rules);
        });
        return PageResponse.of(page, AlertRuleVo.class);
    }

    @Override
    public AlertRuleVo read(Long id) {
        AlertRule alertRule = alertRuleMapper.read(id);
        if (alertRule != null) {
            AlertRuleVo alertRuleVo = BeanUtil.copyProperties(alertRule, AlertRuleVo.class);
            String rules = CharSequenceUtil.format("{}{}{},持续{}个周期就报警",
                    alertRuleVo.getFunctionName(),
                    alertRuleVo.getOperator(),
                    alertRuleVo.getValue(),
                    alertRuleVo.getDuration());
            alertRuleVo.setRules(rules);
            return alertRuleVo;
        }
        return null;
    }

    @Override
    public void update(AlertRuleDto alertRuleDto) {
        AlertRule alertRule = BeanUtil.copyProperties(alertRuleDto, AlertRule.class);
        alertRuleMapper.update(alertRule);
    }

    @Override
    public void delete(Long id) {
        alertRuleMapper.delete(id);
    }

    @Override
    public void updateStatus(Long id, Integer status) {
        alertRuleMapper.updateStatus(id, status);
    }

    @Value("${zzyl.alert.deviceMaintainerRole}")
    private String deviceMaintainerRole;
    //超级管理员的角色名称
    @Value("${zzyl.alert.managerRole}")
    private String managerRole;

    @Override
    public void alertRuleData(DeviceDataVo deviceDataVo) {
        LocalDateTime alarmTime = deviceDataVo.getAlarmTime();
        long between = LocalDateTimeUtil.between(alarmTime, LocalDateTime.now(), ChronoUnit.SECONDS);
        if (between > 60) {
            return;
        }
        List<AlertRule> allAlertRules = alertRuleMapper.selectAll(deviceDataVo.getFunctionId(), deviceDataVo.getProductKey(),"-1" );
        List<AlertRule> theAlertRules = alertRuleMapper.selectAll(deviceDataVo.getFunctionId(), deviceDataVo.getProductKey(), deviceDataVo.getIotId());
        Collection<AlertRule> alertRules = CollUtil.addAll(allAlertRules, theAlertRules);
        if (CollUtil.isEmpty(alertRules)) {
            return;
        }

        alertRules.forEach(alertRule -> {
            devicDataAlarmHandler(deviceDataVo, alertRule);
        });
    }

    private void devicDataAlarmHandler(DeviceDataVo deviceDataVo, AlertRule alertRule) {
        //第一层校验
        String[] split = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime start = LocalTime.parse(split[0]);
        LocalTime end = LocalTime.parse(split[1]);
        LocalTime localTime = LocalDateTimeUtil.of(deviceDataVo.getAlarmTime()).toLocalTime();
        if (localTime.isBefore(start) || localTime.isAfter(end)) {
            return;
        }
        String iotId = deviceDataVo.getIotId();
        String aggCountkey = CacheConstants.ALERT_TRIGGER_COUNT_PREFIX + iotId + ":" + deviceDataVo.getFunctionId() + ":" + alertRule.getId();
        //第二层校验
        int compare = NumberUtil.compare(Double.parseDouble(deviceDataVo.getDataValue()), alertRule.getValue());
        if ((ObjectUtil.equals(alertRule.getOperator(), ">=") && compare >= 0)
                || (ObjectUtil.equals(alertRule.getOperator(), "<") && compare < 0)) {
            log.info("此时设备上报数据达到阈值");
        } else {
            redisTemplate.delete(aggCountkey);
            return;
        }
        //第三层校验
        String s = CacheConstants.ALERT_SILENT_PREFIX + iotId + ":" + deviceDataVo.getFunctionId() + ":" + alertRule.getId();
        String aggCount = (String) redisTemplate.opsForValue().get(s);
        if (ObjectUtil.isNotEmpty(aggCount)) {
            return;
        }
        //第四层校验
        String aggCountData = (String) redisTemplate.opsForValue().get(aggCountkey);
        int count = ObjectUtil.isEmpty(aggCountData) ? 1 : Integer.parseInt(aggCountData) + 1;
        if (ObjectUtil.notEqual(count, alertRule.getDuration())) {
            redisTemplate.opsForValue().set(aggCountkey, String.valueOf(count));
            return;
        }

        redisTemplate.delete(aggCountkey);
        redisTemplate.opsForValue().set(s, String.valueOf(1), alertRule.getAlertSilentPeriod(), TimeUnit.SECONDS);
        List<Long> consumerIds = null;
        if (ObjectUtil.equals(alertRule.getAlertDataType(), 0)) {
            if (ObjectUtil.equals(deviceDataVo.getLocationType(), 0)) {
                consumerIds = deviceMapper.selectNuringIdByIotId(iotId);
            } else if (ObjectUtil.equals(deviceDataVo.getLocationType(), 1) && deviceDataVo.getPhysicalLocationType() == 2) {
                consumerIds = deviceMapper.selectNuringIdByBed(iotId);
            }
        } else {
            consumerIds = userRoleMapper.selectUserRoleByRoleId(alertRule.getId());
        }

        List<Long> managerIds = userRoleMapper.selectUserRoleByRoleId(alertRule.getId());
        List<Long> allConsumerIds = new ArrayList<>();
        allConsumerIds.addAll(consumerIds);
        allConsumerIds.addAll(managerIds);
        allConsumerIds = CollUtil.distinct(allConsumerIds);


        insertAlertData(deviceDataVo, alertRule, allConsumerIds);
        // websocket通知：弹窗消息
        AlertData alertData = BeanUtil.toBean(deviceDataVo, AlertData.class);
        AlertNotifyDto alertNotifyDto = BeanUtil.toBean(alertData, AlertNotifyDto.class);
        alertNotifyDto.setFunctionName(alertRule.getFunctionName());
        alertNotifyDto.setAlertDataType(alertData.getType());
        alertNotifyDto.setNotifyType(1);
        //给指定消费者发送消息
        webSocketServer.sendMessageToConsumer(alertNotifyDto, allConsumerIds);


    }

    private void insertAlertData(DeviceDataVo deviceDataVo, AlertRule alertRule, Collection<Long> allConsumerIds) {
        String format = CharSequenceUtil.format("{} {} {} 持续{}个周期就报警", alertRule.getFunctionName(),
                alertRule.getOperator(), alertRule.getValue(), alertRule.getDuration());
        AlertData alertData = BeanUtil.toBean(deviceDataVo, AlertData.class);
        alertData.setAlertReason(format);
        alertData.setAlertRuleId(alertRule.getId());
        alertData.setStatus(0);
        alertData.setType(alertRule.getAlertDataType());

        List<AlertData> list = allConsumerIds.stream().map(id -> {
            AlertData alertData1 = BeanUtil.copyProperties(alertData, AlertData.class);
            alertData1.setUserId(id);
            return alertData1;
        }).collect(Collectors.toList());
            alertDataMapper.insertList(list);
    }
}


